#include "PackageRecvThread.hpp"

#include "qqdef.hpp"

#include "debug.hpp"
#include "qqclient.hpp"
#include "qqpacket.hpp"
#include "qqsocket.hpp"
#include "packetmgr.hpp"
#include "protocol.hpp"

//for ntohs
#ifdef _WINDOWS
#include <winsock.h>
#include <wininet.h>
#else
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netdb.h>
#endif

extern  void check_ready_packets( qqclient* qq );

static int match_searcher( const void* p, const void* v )
{
	return ( ((qqpacket*)p)->command == ((qqpacket*)v)->command &&
		((qqpacket*)p)->seqno == ((qqpacket*)v)->seqno );
}
static qqpacket* match_packet( qqpacketmgr* mgr, qqpacket* p )
{
	qqpacket* m;
	m = (qqpacket*)loop_search( &mgr->sent_loop, (void*)p, match_searcher );
	return m;
}

//先检查待ack的包中有没有超时的。删除超时的并重发
//如果待ack的队列为空，则继续发包。
int handle_packet( qqclient* qq, qqpacket* p, uchar* data, int len )
{
        qqpacketmgr* mgr = &qq->packetmgr;
        mgr->recv_packets ++;
        std::auto_ptr<bytebuffer> buf(new bytebuffer(data,len));
        //get packet info
        if( qq->network == TCP || qq->network == PROXY_HTTP )
                get_word( buf.get() );	//packet len
        p->head = get_byte( buf.get() );
        p->tail = buf->data[buf->len-1];
        if( p->head != 0x02 || p->tail!=0x03 || buf->len > 2000 ){
                DBG("[%u] wrong packet. len=%d  head: %d  tail: %d", qq->number, buf->len, p->head, p->tail );
                return -1;
        }
        p->version = get_word( buf.get() );
        p->command = get_word( buf.get() );
        p->seqno = get_word( buf.get() );
        uint chk_repeat = (p->seqno<<16)|p->command;
        //是否收到了重复的ack包
        bool isRepeat;
	
                //check repeat
                QMutexLocker ql(&mgr->recv_loop_lock);
		
                std::pair<qqpacketmgr::recv_loop_type::iterator,bool> ret=mgr->recv_loop.insert(chk_repeat);
                isRepeat=!ret.second;
	
        if( !isRepeat){
                QMutexLocker qr(&mgr->sent_loop.mutex);
                for(std::list<qqpacket*>::iterator i=mgr->sent_loop.items.begin();i!=mgr->sent_loop.items.end();++i){
                        if( (*i)->command==p->command && (*i)->seqno==p->seqno){
                                p->match=*i;
                                //DBG_QS(QObject::tr("收到确认包。从sent_loop中删除,command=%1,seq=%2").arg(qqcmdToQString(p->match->command)).arg(p->match->seqno));
                                mgr->sent_loop.items.erase(i);
                                break;
                        }
                }
                p->time_alive = time(NULL);
                //do a test
                if ( !p->buf ){
                        DBG("%u: Error impossible. p->buf: %x  p->command: %x", qq->number, p->buf, p->command );
                        return -1;
                }
                //deal with the packet
                process_packet( qq, p, buf.get() );
                //将temp_loop中的所有包放到ready_loop的最前面。
                moveToHead(&mgr->ready_loop,&mgr->temp_loop,true);
                delete p->match;
                p->match = NULL;
                mgr->failed_packets = 0;
        }else{
                /*QString debugstr=QObject::tr("repeated packet: cmd: %1  seqno:%2").arg(qqcmdToQString(p->command)).arg(p->seqno);
                DBG_QS(debugstr)*/;
        }
        check_ready_packets( qq );
        return 0;
}



void PackageRecvThread::run(){
	DBG("PackageRecvThread started");
	int ret;
	qqpacket* p=new qqpacket();
	qqclient* qq = this->qq_;
	qqpacketmgr* mgr = &qq->packetmgr;
	size_t buffsize=PACKET_SIZE*20;
	uchar* recv_buf=new uchar[buffsize];
	int pos;
	

	if( !p || !recv_buf ){
		DBG("error: p=%x  buf=%x", p, recv_buf );
		delete( p ); 
		delete[] recv_buf ;
		return ;
	}
	pos = 0;
	while( qq->process != P_INIT ){
		//DBG_QS(QObject::tr("开始接收数据。buffer size=%1").arg(PACKET_SIZE-pos));
		ret = qqsocket_recv( qq->socket, recv_buf+pos, buffsize-pos );
		if( ret <= 0 ){
			if( qq->process != P_INIT ){			
				this->sleep(1);
				continue;
			}else{
				break;
			}
		}
		DBG_QS(QObject::tr("接收到%1字节的数据。").arg(ret));
		pos += ret;
		//TCP only
		if( qq->network == TCP || qq->network == PROXY_HTTP ){
			if ( pos > 2 ){
				if( !qq->proxy_established && qq->network == PROXY_HTTP ){
					if( strstr( (char*)recv_buf, "200" )!=NULL ){
						DBG("proxy server reply ok!");
						qq->proxy_established = 1;
						pos=0;
						prot_login_touch( qq );
						//手动添加到发送队列。
						moveToHead(&mgr->ready_loop,&mgr->temp_loop,true);
						//检查待发送包
						check_ready_packets( qq );
					}else{
						DBG("proxy server reply failure!");
						recv_buf[ret]=0;
						DBG( "%s", recv_buf );
						qqclient_set_process( qq, P_ERROR );
					}
				}else{
					//最前面16个字节是包长。
					int len;
					while(len= ntohs(*(ushort*)recv_buf)){
					//如果确实已经收到了一个完整的包
					if( pos >= len )	//a packet is O.K.
					{
						if( handle_packet( qq, p, recv_buf, len ) < 0 ) {
							pos = 0;
							continue;
						}
						pos -= len;
						//将rdptr移到buffer的头部。
						if( pos > 0 ){
							memmove( recv_buf, recv_buf+len, pos );
						}
					}else if( pos == buffsize ){
						DBG("error: pos: 0x%x ", pos );
						pos = 0;
					} else break;
					}
				}
			}
		}else{	//UDP
			handle_packet( qq, p, recv_buf, ret );
			pos = 0;
		}
	}
	delete[] recv_buf ;
	packetmgr_del_packet( mgr, p );
	DBG("end.");
	return;
}
